﻿using ArtMath.Attribute;
using ArtMath.Component.Point;
using ArtMath.Core.Data;
using ArtMath.Core.Helper;
using ArtMath.PointCollection;
using ArtMath.Resource;
using System;
using System.Collections.Generic;

namespace ArtMath.Component.Circle
{
    /// <summary>
    /// 三点部分圆基类
    /// </summary>
    [Serializable]
    public abstract class ThreePointsPartialCircleBase : PartialCircleBase
    {
        public ThreePointsPartialCircleBase(SketchPad pad, string name, ToolTypeName toolType, bool addToList = true) : base(pad, name, toolType, addToList)
        {
            InPoints = new PointBase[3];
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("{0}1", "EndPoint")]
        public PointBase Point1
        {
            get { return InPoints[0]; }
            set { SetPoint(0, value); }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("{0}2", "EndPoint")]
        public PointBase Point2
        {
            get { return InPoints[1]; }
            set { SetPoint(1, value); }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("PassPoint")]
        public PointBase MidPoint
        {
            get { return InPoints[2]; }
            set { SetPoint(2, value); }
        }
        public override PointD NewCenter
        {
            get
            {
                return Utility.GetCenter(Point1.NewXY, Point2.NewXY, MidPoint.NewXY);
            }
        }
        public override double NewRadius
        {
            get
            {
                return NewCenter.DistanceTo(Point1.NewXY);
            }
        }
        public override PointD NewPCenter
        {
            get
            {
                return Pad.XYToPxy(NewCenter);
            }
        }
        public override bool CanDrawVirtual
        {
            get
            {
                if (OrderIndex == 0)
                {
                    if (MidPoint != null)
                    {
                        return true;
                    }
                }
                else
                {
                    if (Point2 != null)
                    {
                        return true;
                    }
                }
                return false;
            }
        }
        public override double NewStart
        {
            get { return NewCenter.GetAngle(Point1.NewXY); }
        }
        public override double NewSweep
        {
            get
            {
                double tmp = Utility.GetAngle(NewCenter, Point1.NewXY, Point2.NewXY);
                if (Utility.OnSameSide(Point1.NewPxy, Point2.NewPxy, MidPoint.NewPxy, NewPCenter))
                {
                    tmp = Core.Helper.Angle.RadRound - tmp;
                }
                tmp *= Utility.Sign(Point1.NewPxy, MidPoint.NewPxy, Point2.NewPxy) * (Point1.NewPxy.X > MidPoint.NewPxy.X ? -1 : 1);
                return tmp;
            }
        }
        public override double NewPStart
        {
            get
            {
                double tmp = NewPCenter.GetAngle(Point1.NewPxy);
                if (Pad.Coordinate != null)
                {
                    tmp += Pad.Coordinate.RotateAngle.RadValue;
                }
                return tmp;
            }
        }
        public override double NewPSweep
        {
            get
            {
                double tmp = Utility.GetAngle(NewPCenter, Point1.NewPxy, Point2.NewPxy);
                if (Utility.OnSameSide(Point1.NewPxy, Point2.NewPxy, MidPoint.NewPxy, NewPCenter))
                {
                    tmp = Core.Helper.Angle.RadRound - tmp;
                }
                tmp *= Utility.Sign(Point1.NewPxy, MidPoint.NewPxy, Point2.NewPxy) * (Point1.NewPxy.X > MidPoint.NewPxy.X ? 1 : -1);
                return tmp;
            }
        }
        public override double NewChordLength
        {
            get { return Point1.NewXY.DistanceTo(Point2.NewXY); }
        }
        public override void ComponentBuilding(Base component)
        {
            double[] gets;
            if (OrderIndex == 0)
            {
                if (MidPoint == null || (gets = Pad.CalcArcParams(Point1, MidPoint.ToPointD(), MidPoint.Pxy, null, SpareCoordinate,
                    ref ske.Center, ref pske.Center)) == null)
                {
                    ShowStatus($"{Resources.Translate("Creating")}{Resources.ColonSeparate}{Name}");
                    return;
                }
            }
            else
            {
                if (Point2 == null || (gets = Pad.CalcArcParams(Point1, null, SpareCoordinate, Point2.ToPointD(), Point2.Pxy,
                    ref ske.Center, ref pske.Center)) == null)
                {
                    ShowStatus($"{Resources.Translate("Creating")}{Resources.ColonSeparate}{Name}");
                    return;
                }
            }
            PartialCircle pc = ske as PartialCircle;
            PartialEllipse pe = pske as PartialEllipse;
            Radius = gets[1];
            ArcLength = gets[2];
            ChordLength = gets[3];
            pc.Start = gets[4];
            pe.Start = gets[5];
            pc.Sweep = gets[6];
            pe.Sweep = gets[7];
            Circumference = ArcLength;
            Area = Math.PI * Radius * Radius * gets[0];
            ReCalcParams(true);
            Pad.BuildArcSamples(ske.Curves[0], pske.Curves[0], Center, Radius, Start, Sweep);
            base.ComponentBuilding(component);
        }
        protected virtual void ReCalcParams(bool fromBuilding)
        {

        }
        public override void ComponentChanged(ShapeBase component)
        {
            base.ComponentChanged(component);
            Circumference = ArcLength;
            Area = Math.PI * Radius * Radius * CentralAngle / Core.Helper.Angle.RadRound;
            ReCalcParams(false);
        }
        protected override void ClickOrder(IList<PointCreatingArgs> args, int clickTimes, Predicate<PointCreatingArgs> act)
        {
            if (act == null) return;
            if (OrderIndex == 0)
            {
                if (!act(args[0])) return;
                if (!act(args[2])) return;
                if (!act(args[1])) return;
                return;
            }
            base.ClickOrder(args, clickTimes, act);
        }
        public override void CreateComponents()
        {
            if (OrderIndex == 0)
            {
                if (Point1 == null)
                {
                    Point1 = Pad.CreatePoint($"{Resources.Translate("EndPoint")}1", SpareCoordinate_);
                    Pad.TrackObj = this;
                }
                else if (MidPoint == null)
                {
                    MidPoint = Pad.CreatePoint(Resources.Translate("PassPoint"), SpareCoordinate_, true, new PointCollectionBase[] { new Universal(Point1.ToPointD()) });
                }
                else
                {
                    Point2 = Pad.CreatePoint($"{Resources.Translate("EndPoint")}2", SpareCoordinate_, true, new PointCollectionBase[] { new Universal(Point1.ToPointD(), Point1.GetSlope(MidPoint)) });
                    base.CreateComponents();
                }
            }
            else
            {
                if (Point1 == null)
                {
                    Point1 = Pad.CreatePoint($"{Resources.Translate("EndPoint")}1", SpareCoordinate_);
                    Pad.TrackObj = this;
                }
                else if (Point2 == null)
                {
                    Point2 = Pad.CreatePoint($"{Resources.Translate("EndPoint")}2", SpareCoordinate_, true, new PointCollectionBase[] { new Universal(Point1.ToPointD()) });
                }
                else
                {
                    MidPoint = Pad.CreatePoint(Resources.Translate("PassPoint"), SpareCoordinate_, true, new PointCollectionBase[] { new Universal(Point1.ToPointD(), Point1.GetSlope(Point2)) });
                    base.CreateComponents();
                }
            }
        }
    }
}
